package org.baicaixiaozhan.tenet.base;

import java.io.Serializable;
import java.security.SecureRandom;

/**
 * DESC: 简单扩展 UUID v4 生成是否存在分割线
 *
 * @author baicaixiaozhan
 * @since 1.0.0
 */
public class SimpleUUIDs implements Serializable {

    private final long mostSigBits;

    private final long leastSigBits;

    private static class Holder {
        static final SecureRandom numberGenerator = new SecureRandom();
    }

    public SimpleUUIDs(long mostSigBits, long leastSigBits) {
        this.mostSigBits = mostSigBits;
        this.leastSigBits = leastSigBits;
    }

    private SimpleUUIDs(byte[] data) {
        long msb = 0;
        long lsb = 0;
        assert data.length == 16 : "data must be 16 bytes in length";
        for (int i=0; i<8; i++)
            msb = (msb << 8) | (data[i] & 0xff);
        for (int i=8; i<16; i++)
            lsb = (lsb << 8) | (data[i] & 0xff);
        this.mostSigBits = msb;
        this.leastSigBits = lsb;
    }

    public static SimpleUUIDs randomUUID() {
        SecureRandom ng = SimpleUUIDs.Holder.numberGenerator;

        byte[] randomBytes = new byte[16];
        ng.nextBytes(randomBytes);
        randomBytes[6]  &= 0x0f;
        randomBytes[6]  |= 0x40;
        randomBytes[8]  &= 0x3f;
        randomBytes[8]  |= 0x80;
        return new SimpleUUIDs(randomBytes);
    }

    public String toString() { return toString(true); }

    public String toSimple() { return toString(false); }

    public String toString(boolean enableDividingLine) {
        return (digits(mostSigBits >> 32, 8) + (enableDividingLine ? "-" : "") +
                digits(mostSigBits >> 16, 4) + (enableDividingLine ? "-" : "") +
                digits(mostSigBits, 4) + (enableDividingLine ? "-" : "") +
                digits(leastSigBits >> 48, 4) + (enableDividingLine ? "-" : "") +
                digits(leastSigBits, 12));
    }

    private static String digits(long val, int digits) {
        long hi = 1L << (digits * 4);
        return Long.toHexString(hi | (val & (hi - 1))).substring(1);
    }

    public int hashCode() {
        long hilo = mostSigBits ^ leastSigBits;
        return ((int)(hilo >> 32)) ^ (int) hilo;
    }

    public boolean equals(Object obj) {
        if ((null == obj) || (obj.getClass() != SimpleUUIDs.class))
            return false;
        SimpleUUIDs id = (SimpleUUIDs) obj;
        return (mostSigBits == id.mostSigBits &&
                leastSigBits == id.leastSigBits);
    }
}
